//
//  QXSocketManager.m
//  Pods
//
//  Created by Qianxia on 2017/1/5.
//
//

#import "QXSocketManager.h"
#import "QXDataManager.h"
#import "QXDriverConfiguration.h"

#ifdef DEBUG
#   define QXDLog(fmt, ...) NSLog((@"------------------------------------------------------ \n %s [Line %d] \n------------------------------------------------------" fmt), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__);
#else
#   define QXDLog(...)
#endif



NSString * const ReloginNotificationKey = @"ReloginNotificationKey";

NSString * const UPLOAD_LOCATION_RESPONSEKEY = @"UPLOAD_LOCATION_RESPONSE";

/// 心跳时间
NSInteger const HEARTBEAT_SEND_INTERVAL = 15;
NSInteger const HEARTBEAT_TIMEOUT_Times = 3;
NSString * const QXSocketUrlKey = @"com.qianxx.socket.url";


static id manager;
static NSString *baseUrl;

@interface QXSocketManager ()

/**
 长连接管理
 */
@property (strong, nonatomic) SRWebSocket *webSocket;

/**
 注册通知
 */
@property (strong, nonatomic) NSMutableDictionary *notificationKeys;

/**
 用户信息
 */
@property (strong, nonatomic) NSMutableDictionary *userInfo;

/**
 登录字典
 */
@property (strong, nonatomic) NSMutableDictionary *loginParams;



/**
 发送心跳
 */
@property (strong, nonatomic) NSTimer *sendHeartbeatTimer;

/**
 监测连接状态
 */
@property (strong, nonatomic) NSTimer *checkConnectTimer;

/**
 发送心跳次数
 */
@property (assign, nonatomic) NSInteger sendHeartbeatTimes;

/**
 记录乘客端pushUuid  反馈给服务器
 */
@property (copy, nonatomic) NSString *pushUuid;


/**
 记录登录状态---乘客或者司机
 */
@property (assign, nonatomic) BOOL *isDriver;


@end

@implementation QXSocketManager

/**
 设置连接url
 
 @param url 连接url
 */
+ (void)setUrl:(NSString *)url {
    baseUrl = url;
    [QXDataManager saveValue:url forKey:QXSocketUrlKey];
}

/**
 Returns the singleton instance of this class.
 */
+ (instancetype)manager {
    
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        manager = [[self alloc] init];
    });
    return manager;
}

- (instancetype)init {
    self = [super init];
    if (self) {
        [self initializationData];
    }
    return self;
}


/**
 初始化数据
 */
- (void)initializationData {
    // 初始化通知
    self.notificationKeys = [NSMutableDictionary dictionary];
    self.userInfo = [NSMutableDictionary dictionary];
    self.sendHeartbeatTimes = 0;
    
    // 长连接地址
    if (!baseUrl) {
        baseUrl = [QXDataManager getValueForKey:QXSocketUrlKey];
    }
    
    // 连接状态
    self.status = QXSocketConnectionStatusClosed;
}

/**
 登录

 @param userId 用户uuId
 @param token 登录token
 @param isDriver 是否是司机端
 */
- (void)loginWithUserId:(NSString *)userId token:(NSString *)token isDriver:(BOOL)isDriver {
    
    // 连接状态
    self.status = QXSocketConnectionStatusClosed;
    
    // 记录是司机Or乘客用户
    self.isDriver = isDriver;
    
    // 保存用户信息
    [self.userInfo removeAllObjects];
    [self.userInfo setValue:userId forKey:@"clientUuid"];
    [self.userInfo setValue:token forKey:@"token"];
    
    // 保存登录信息
    self.loginParams = [NSMutableDictionary dictionaryWithDictionary:self.userInfo];
    [self.loginParams setValue:isDriver ? @"DRIVER" : @"PASSENGER" forKey:@"from"];
    [self.loginParams setValue:@"LOGIN" forKey:@"type"];
    [self.loginParams setValue:[QXDataManager getValueForKey:QXAppId] forKey:@"appid"];
    
    // 重新连接
    [self reconnect];
}


/**
 重新连接
 */
- (void)reconnect {
    
    // 长连接地址
    if (!baseUrl) {
        baseUrl = [QXDataManager getValueForKey:QXSocketUrlKey];
        if (!baseUrl) {
            NSAssert(NO, @"请先设置[QXSocketManager setUrl:QXSocketUrl]");
        }
    }
    
    // 如果长连接不处于关闭状态，则不需要重新连接
    if (self.status != QXSocketConnectionStatusClosed) {
        return;
    }
    
    // 关闭之前的连接
    [self close];
    
    // 设置状态连接中
    self.status = QXSocketConnectionStatusConnecting;
    
    // 长连接
    NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:baseUrl]];
    self.webSocket = [[SRWebSocket alloc] initWithURLRequest:request];
    self.webSocket.delegate = self;
    [self.webSocket open];
}


/**
 关闭长连接
 */
- (void)close {
    self.webSocket.delegate = nil;
    [self.webSocket close];
    self.webSocket = nil;
    
    // 移除心跳
    [self.sendHeartbeatTimer invalidate];
    self.sendHeartbeatTimer = nil;
    // 移除自动连接
    [self.checkConnectTimer invalidate];
    self.checkConnectTimer = nil;
    // 设置状态连接中
    self.status = QXSocketConnectionStatusClosed;
}


- (void)login {
    if (!self.loginParams) {
        return;
    }
    
    [self send:self.loginParams];
}

/**
 发送心跳

 @param timer 定时器
 */
- (void)sendHeartbeat:(NSTimer *)timer {
    
    if (self.status != QXSocketConnectionStatusRunning) {
        return;
    }
    
    // 发送心跳三次无响应，则重新连接
    if (self.sendHeartbeatTimes >= HEARTBEAT_TIMEOUT_Times) {
        self.sendHeartbeatTimes = 0;
        self.status = QXSocketConnectionStatusClosed;
        [self reconnect];
        return;
    }
    
    self.sendHeartbeatTimes += 1;
    
    NSDictionary *params = @{@"type": @"HEART_BEAT", @"heartBeatTime": @((NSInteger)[[NSDate date] timeIntervalSince1970] * 1000)};
    [self send:params];
}

/**
 发送数据

 @param data 字典
 */
- (void)send:(NSDictionary *)data {
    if (self.webSocket.readyState != SR_OPEN) {
        return;
    }
    
    NSError *error;
    NSMutableDictionary *params = [NSMutableDictionary dictionaryWithDictionary:data];
    [params addEntriesFromDictionary:self.userInfo];
    NSData *jsonData = [NSJSONSerialization dataWithJSONObject:params options:0 error:&error];
    
    if (error) {
        QXDLog(@"%@", error.localizedDescription);
    }
    
    [self.webSocket send:[[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding]];
}


/**
 检查长连接
 */
- (void)checkConnect {
    
    // 发送心跳
    if (!self.sendHeartbeatTimer) {
        self.sendHeartbeatTimer = [NSTimer scheduledTimerWithTimeInterval:HEARTBEAT_SEND_INTERVAL target:self selector:@selector(sendHeartbeat:) userInfo:nil repeats:YES];
    }
    
    if (!self.checkConnectTimer) {
        self.checkConnectTimer = [NSTimer scheduledTimerWithTimeInterval:10.0 target:self selector:@selector(reconnect) userInfo:nil repeats:YES];
    }
    
}



#pragma mark - 业务处理

/**
 注册长连接类型
 
 @param type 长连接类型
 @param notificationName 通知名称
 */
- (void)registerType:(NSString *)type notificationName:(NSString *)notificationName {
    
    id allNotificationNames = self.notificationKeys[type];
    if (allNotificationNames) {
        // 已有注册该通知
        if ([allNotificationNames isKindOfClass:[NSArray class]]) {
            // 该type有多个通知
            if (![allNotificationNames containsObject:notificationName]) {
                NSMutableArray *items = [NSMutableArray arrayWithArray:allNotificationNames];
                [items addObject:notificationName];
                [self.notificationKeys setValue:items forKey:type];
            }
            
        } else if ([allNotificationNames isKindOfClass:[NSString class]]) {
            // 只有一个通知
            NSArray *items = [NSArray arrayWithObjects:allNotificationNames, notificationName, nil];
            [self.notificationKeys setValue:items forKey:type];
        }
        
    } else {
        // 注册type
        [self.notificationKeys setValue:notificationName forKey:type];
    }
}

- (void)removeNotificationType:(NSString *)type notificationName:(NSString *)notificationName {
    
    id allNotificationNames = self.notificationKeys[type];
    // 已有注册该通知
    if ([allNotificationNames isKindOfClass:[NSArray class]]) {
        // 该type有多个通知
        NSMutableArray *items = [NSMutableArray arrayWithArray:allNotificationNames];
        [items removeObject:notificationName];
        if (items.count == 0) {
            items = nil;
        }
        
        [self.notificationKeys setValue:items forKey:type];
        
    } else if ([allNotificationNames isKindOfClass:[NSString class]]) {
        // 只有一个通知
        [self.notificationKeys removeObjectForKey:type];
    }
        
    
}

#pragma mark - SRWebSocketDelegate

// message will either be an NSString if the server is using text
// or NSData if the server is using binary.
- (void)webSocket:(SRWebSocket *)webSocket didReceiveMessage:(id)message {
    QXDLog(@"收到消息----------- \n %@ --------------------\n\n", message);
    
    if ([message isKindOfClass:[NSString class]]) {
        NSError *error;
        NSDictionary *dataDictionary = [NSJSONSerialization JSONObjectWithData:[message dataUsingEncoding:NSUTF8StringEncoding] options:0 error:&error];
        if (error) {
            QXDLog(@"%@", error.localizedDescription);
            return;
        }
        
        // 登录成功
        if ([[dataDictionary valueForKey:@"type"] isEqualToString:@"LOGIN_RESPONSE"]) {
            
            // 保存长连接，启动心跳
            [self checkConnect];
            return;
        } else if ([[dataDictionary valueForKey:@"type"] isEqualToString:@"LOGIN"]) {
            // 需要重新登录
            [[NSNotificationCenter defaultCenter] postNotificationName:ReloginNotificationKey object:dataDictionary];
            return;
        } else if ([[dataDictionary valueForKey:@"type"] isEqualToString:@"HEART_BEAT"]) {
            // 收到心跳
            self.sendHeartbeatTimes = 0;
            
            return;
        } else if ([[dataDictionary valueForKey:@"type"] isEqualToString:@"PUSH"]) {
            
            NSString *contentString = [dataDictionary valueForKey:@"content"];
            
            
            NSDictionary *contentDictionary = [NSJSONSerialization JSONObjectWithData:[contentString dataUsingEncoding:NSUTF8StringEncoding] options:0 error:&error];
            
            if (error) {
                QXDLog(@"%@", error.localizedDescription);
                return;
            }
            
            if (!self.isDriver){
                if ([self.pushUuid isEqualToString:contentDictionary[@"pushUuid"]]) {
                    return;
                } else {
                    self.pushUuid = contentDictionary[@"pushUuid"];
                    [self send:@{@"clientUuid":[dataDictionary valueForKey:@"clientUuid"] ,@"pushUuid":self.pushUuid,@"retry":@(0),@"success":@(YES),@"type":@"PUSH_RESPONSE"}];
                }
            }
            
            NSString *opCode = [[contentDictionary valueForKey:@"opCode"] description];
            if (opCode) {
                id allNotificationNames = self.notificationKeys[opCode];
                // 已有注册该通知
                if ([allNotificationNames isKindOfClass:[NSArray class]]) {
                    // 该type有多个通知
                    [(NSArray *)allNotificationNames enumerateObjectsUsingBlock:^(NSString *  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
                        [[NSNotificationCenter defaultCenter] postNotificationName:obj object:contentDictionary];
                    }];
                    
                } else if ([allNotificationNames isKindOfClass:[NSString class]]) {
                    // 只有一个通知
                    [[NSNotificationCenter defaultCenter] postNotificationName:allNotificationNames object:contentDictionary];
                } else if ([opCode integerValue] == 3007) {
                    [[NSNotificationCenter defaultCenter] postNotificationName:@"AdjustThePrice" object:contentDictionary];
                } else if ([opCode integerValue] == 1008) {
                    [[NSNotificationCenter defaultCenter] postNotificationName:@"DriverSuccessfulPaymentNotificationKey" object:contentDictionary];
                }
            }
        }else if ([[dataDictionary valueForKey:@"type"] isEqualToString:@"UPLOAD_LOCATION_RESPONSE"]) { // 上传位置收到的报文,这里可以获取超时等待费
            
            // 只有一个通知
            [[NSNotificationCenter defaultCenter] postNotificationName:UPLOAD_LOCATION_RESPONSEKEY object:dataDictionary];
            
        } else {
            
            NSString *type = [dataDictionary valueForKey:@"type"];
            
            if (type) {
                id allNotificationNames = self.notificationKeys[type];
                // 已有注册该通知
                if ([allNotificationNames isKindOfClass:[NSArray class]]) {
                    // 该type有多个通知
                    [(NSArray *)allNotificationNames enumerateObjectsUsingBlock:^(NSString *  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
                        [[NSNotificationCenter defaultCenter] postNotificationName:obj object:dataDictionary];
                    }];
                    
                } else if ([allNotificationNames isKindOfClass:[NSString class]]) {
                    // 只有一个通知
                    [[NSNotificationCenter defaultCenter] postNotificationName:allNotificationNames object:dataDictionary];
                }
            }
        }
        
        // 处理内容
        
    }
}


- (void)webSocketDidOpen:(SRWebSocket *)webSocket {
    QXDLog(@"已连接");
    
    // 连接成功
    self.status = QXSocketConnectionStatusRunning;
    
    // 登录
    [self login];
}

- (void)webSocket:(SRWebSocket *)webSocket didFailWithError:(NSError *)error {
    QXDLog(@"连接失败----------- \n %@ --------------------\n\n", error.localizedDescription);
    // 连接失败
    self.status = QXSocketConnectionStatusClosed;
}

- (void)webSocket:(SRWebSocket *)webSocket didCloseWithCode:(NSInteger)code reason:(NSString *)reason wasClean:(BOOL)wasClean {
    QXDLog(@"关闭连接----------%@", reason);
    // 连接失败
    self.status = QXSocketConnectionStatusClosed;
}

- (void)webSocket:(SRWebSocket *)webSocket didReceivePong:(NSData *)pongPayload {

//    NSLog(@"%@", [[NSString alloc] initWithData:pongPayload encoding:NSUTF8StringEncoding]);
}

// Return YES to convert messages sent as Text to an NSString. Return NO to skip NSData -> NSString conversion for Text messages. Defaults to YES.
//- (BOOL)webSocketShouldConvertTextFrameToString:(SRWebSocket *)webSocket {
//    
//}


@end
